Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 19, 2025

Plan to Fix DURABLE2003 False Positives for Cross-Assembly Activities

  • Understand the issue: Analyzer only scans current compilation, not referenced assemblies
  • Understand the analyzer code structure
  • Build and test the analyzer successfully
  • Modify FunctionNotFoundAnalyzer to scan referenced assemblies for activity/orchestrator definitions
  • Add logic to find [Function] + [ActivityTrigger] methods in referenced assemblies
  • Add logic to find TaskActivity-derived classes in referenced assemblies
  • Add logic to find ITaskOrchestrator implementations in referenced assemblies
  • Create test to validate cross-assembly activity detection
  • Run tests to verify fix (all 20 tests passing)
  • Run full analyzer test suite (all 122 tests passing)
  • Address code review feedback (assembly filtering and test comment updates)
  • Refactor code to extract helper methods and improve maintainability
  • Fix duplicate XML documentation
  • Filter to only scan assemblies that reference Durable Task types
  • Remove Microsoft.DurableTask.Abstractions (transitive dependency only)
  • Replace assembly reference checking with semantic lookup
  • Optimize to avoid double traversal of namespace tree
  • Complete - All changes implemented and tested
Original prompt

This section details on the original issue you should resolve

<issue_title>Roslyn Analyzer to detect calls to non-existent functions fails, when Activity function defined in other assembly than orchestrator</issue_title>
<issue_description>The Roslyn analyzer introduced in version 1.12.1 incorrectly reports warning DURABLE2003 when an activity function is defined in a separate assembly from the orchestrator, even though the function is correctly defined and works at runtime.

Package Version
• Working version: Microsoft.Azure.Functions.Worker.Extensions.DurableTask 1.12.0
• Affected version: Microsoft.Azure.Functions.Worker.Extensions.DurableTask 1.12.1

Expected Behavior

No warning should be raised when an activity function is correctly defined in a referenced assembly. The analyzer should be able to detect activity functions across assembly boundaries.

Actual Behavior

The analyzer emits the following warning:

DurableOrchestrator\Function1.cs(23,27,23,88): warning DURABLE2003: The activity function 'SayHello' was not found in the current compilation. Ensure the activity is defined and the name matches exactly.

Steps to Reproduce

  1. Create a new Azure Function project from the standard template with Orchestrator function
  2. Create a separate class library project (e.g., ActivityFunctions)
  3. Move the SayHello activity function to the separate assembly
  4. Add a project reference from the orchestrator project to the ActivityFunctions project
  5. Update Microsoft.Azure.Functions.Worker.Extensions.DurableTask to version 1.12.1</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits December 19, 2025 18:15
Modified FunctionNotFoundAnalyzer to scan referenced assemblies for activity and orchestrator definitions. Added ScanReferencedAssemblies and ScanNamespaceForFunctions methods to detect functions defined in other assemblies. Added three new tests to verify cross-assembly detection works correctly.

Co-authored-by: YunchuWang <[email protected]>
Add assembly filtering to skip system assemblies for performance. Update test comments to accurately describe that they simulate cross-assembly scenarios using separate source files in the same compilation.

Co-authored-by: YunchuWang <[email protected]>
Extract helper methods IsActivityMethod, IsOrchestratorMethod, and ImplementsInterface to reduce code duplication. Move system assembly names to static readonly collections. Optimize LINQ chain in ScanReferencedAssemblies to use simple foreach loop.

Co-authored-by: YunchuWang <[email protected]>
Copilot AI changed the title [WIP] Fix Roslyn analyzer to detect activity functions correctly Fix DURABLE2003 false positive when activities are in referenced assemblies Dec 19, 2025
Copilot AI requested a review from YunchuWang December 19, 2025 18:30
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
@YunchuWang
Copy link
Member

@copilot it will scan all assemblies including transitive dependencies? we should only scan assemblies that relevant meaning the ones customers have defined activity or (sub) orchestration.

Add ShouldScanAssembly method that checks if an assembly references Durable Task types (Microsoft.DurableTask.Abstractions, Microsoft.DurableTask.Worker, or Microsoft.Azure.Functions.Worker.Extensions.DurableTask) before scanning. This prevents scanning of transitive dependencies that don't contain activities or orchestrators, improving performance and reducing false positives.

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Dec 19, 2025

@copilot it will scan all assemblies including transitive dependencies? we should only scan assemblies that relevant meaning the ones customers have defined activity or (sub) orchestration.

Fixed in b1009a6. Added ShouldScanAssembly method that checks if an assembly references Durable Task types (Microsoft.DurableTask.Abstractions, Microsoft.DurableTask.Worker, or Microsoft.Azure.Functions.Worker.Extensions.DurableTask) before scanning it. This ensures we only scan assemblies that customers have defined activities or orchestrations in, skipping transitive dependencies that don't contain Durable Task functions.

@YunchuWang
Copy link
Member

@copilot why scan for Microsoft.DurableTask.Abstractions reference?

Microsoft.DurableTask.Abstractions is a transitive dependency that users never directly reference. Users reference either Microsoft.DurableTask.Worker (for non-function scenarios) or Microsoft.Azure.Functions.Worker.Extensions.DurableTask (for Azure Functions), both of which transitively bring in the abstractions package. Updated ShouldScanAssembly to only check for packages users actually reference.

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Dec 19, 2025

@copilot why scan for Microsoft.DurableTask.Abstractions reference?

Removed in 7d44132. Microsoft.DurableTask.Abstractions is a transitive dependency - users never directly reference it. Users reference either Microsoft.DurableTask.Worker (non-function scenarios) or Microsoft.Azure.Functions.Worker.Extensions.DurableTask (Azure Functions), which both transitively bring in the abstractions package. Now only checking for packages users actually reference.

@YunchuWang
Copy link
Member

@copilot scanning assemblies references this way is too fragile, the scanning logic should be to if IsSystemAssembly(assembly)
skip

if ContainsDurableSymbols(assembly) // semantic lookup
scan this assembly

else
skip

Replace fragile assembly reference checking with semantic lookup using ContainsDurableSymbols. This checks if an assembly contains any Durable Task types (TaskActivity, ITaskOrchestrator, ActivityTriggerAttribute, OrchestrationTriggerAttribute) by examining the symbol tree, which is more robust and maintainable than checking package references.

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Dec 19, 2025

@copilot scanning assemblies references this way is too fragile, the scanning logic should be to if IsSystemAssembly(assembly)
skip

...

Implemented in e94bcd5. Replaced assembly reference checking with semantic lookup via ContainsDurableSymbols that examines the symbol tree for Durable Task types (TaskActivity, ITaskOrchestrator, ActivityTriggerAttribute, OrchestrationTriggerAttribute). This is more robust and won't break if package names change.

@YunchuWang
Copy link
Member

@copilot ScanNamespaceForFunctions(
assembly.GlobalNamespace, this can be a performance concern right

Removed ShouldScanAssembly and ContainsDurableSymbols methods that caused the namespace tree to be traversed twice (once to check if assembly has Durable symbols, then again to collect function names). Now directly calls ScanNamespaceForFunctions which does all the work in a single pass. IsSystemAssembly already filters out the vast majority of irrelevant assemblies.

Co-authored-by: YunchuWang <[email protected]>
Copy link
Contributor Author

Copilot AI commented Dec 19, 2025

@copilot ScanNamespaceForFunctions(
assembly.GlobalNamespace, this can be a performance concern right

Fixed in 9f8c8ed. Removed the duplicate traversal - previously ShouldScanAssembly would traverse the namespace tree to check for Durable symbols, then ScanNamespaceForFunctions would traverse it again to collect function names. Now we only traverse once via ScanNamespaceForFunctions. IsSystemAssembly already filters out most assemblies, so scanning remaining user assemblies is acceptable.

@YunchuWang
Copy link
Member

this is too fragile to check referenced assemlibes

@YunchuWang
Copy link
Member

closing

@YunchuWang YunchuWang closed this Dec 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Roslyn Analyzer to detect calls to non-existent functions fails, when Activity function defined in other assembly than orchestrator

2 participants